using System;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;

public class CharacterBase
{
    private string name;
    private  ControllerBase owner;
    
    #region 事件
    public Action<float> OnReduceHealth;//当生命减少
    public Action<float> OnReduceDefense;//当防御减少
    public Action<float> OnFireDamage;//当受到火伤害
    public Action<float> OnIceDamage;//当受到冰伤害
    public Action<float> OnElectricDamage;//当受到电伤害
    public  Action<float> OnCrit;//当暴击
    public Action OnDodge;//当闪避
    public Action OnDead;//当死亡
    
    public Action OnFireStatusStart;//当受到火状态
    public Action OnFireStatusEnd;
    public Action OnIceStatusStart;
    public Action OnIceStatusEnd;
    public Action OnElectricStatusStart;
    public Action OnElectricStatusEnd;
    #endregion
    
    #region 状态
    protected bool isDead;//是否死亡
    protected bool isBurning;//是否被烧烧
    protected float burningTime;
    protected float burnDely;  //燃烧间隔
    protected  bool isFrozen;//是否被冰冻
    protected float frozenTime;
    protected bool isEasyDamage;//是否易伤状态
    protected float easyDamageTime;
    public bool IsDead()
    {
        return isDead;
    }
    public void ForceDead(bool isDead)
    {
        GetStat(StatType.CurrentHealth).SetValue(0);
        this.isDead = isDead;
    }
    public void ForceFrozen(bool isFrozen,float time)
    {
        frozenTime = time;
        this.isFrozen = isFrozen;
    }
    public bool IsFrozen()
    {
        return isFrozen;
    }

    public void ForceBurning(bool isBurning,float time)
    {
        burningTime = time;
        this.isBurning = isBurning;
    }
    public bool IsBurning()
    {
        return isBurning;
    }
    public void ForceEasyDamage(bool isEasyDamage,float time)
    {
        easyDamageTime = time;
        this.isEasyDamage = isEasyDamage;
    }
    public bool IsEasyDamage()
    {
        return isEasyDamage;
    }

    public virtual void Update()
    {
        if (isDead)
        {
            return;
        }
        if (isBurning)
        {
            burningTime -= Time.deltaTime;
            if (burningTime<=0)
            {
                isBurning = false;
                //关闭ui燃烧显示
                OnFireStatusEnd?.Invoke();
            }
            else
            {
                //间隔burnDely触发一次燃烧
                if (burnDely<=0)
                {
                    burnDely = Setting.burningDely;
                    Debuger.LogRed($"{name}被烧烧了");
                    //最大生命值的%5
                    var damage = GetValue(StatType.MaxHealth)*0.05f;
                    damage = Mathf.Ceil(damage);
                    OnFireDamage?.Invoke(damage);
                    DoBuffDamage(damage);
                }
                else
                {
                    burnDely -= Time.deltaTime;
                }
            }
        }
        //火焰，冰冻，易伤持续时间倒计时
        if (isFrozen)
        {
            frozenTime -= Time.deltaTime;
            if (frozenTime<=0)
            {
                isFrozen = false;
                //解冻
                owner.ForceForzen(false);
                //通知ui寒冷状态结束
                OnIceStatusEnd?.Invoke();
            }
        }
        if (isEasyDamage)
        {
            easyDamageTime -= Time.deltaTime;
            if (easyDamageTime<=0)
            {
                isEasyDamage = false;
                //关闭ui易伤显示
                OnElectricStatusEnd?.Invoke();
            }
        }
        
    }
    #endregion

    #region 数值
    protected Dictionary<StatType, Stat> stats;
    public CharacterBase(string name,ControllerBase controller)
    {
        owner = controller;
        this.name = name;
        stats  = new Dictionary<StatType, Stat>();
        stats.Add(StatType.Damage, new Stat());
        stats.Add(StatType.CurDefense, new Stat());
        stats.Add(StatType.MaxDefense, new Stat());
        stats.Add(StatType.CritRate, new Stat());
        stats.Add(StatType.CritDamage, new Stat());
        stats.Add(StatType.DodgeRate, new Stat());
        stats.Add(StatType.MaxHealth, new Stat());
        stats.Add(StatType.CurrentHealth, new Stat());
        
        stats.Add(StatType.MagicResistance, new Stat());
        stats.Add(StatType.FireDamage, new Stat());
        stats.Add(StatType.CurFireValue, new Stat());
        stats.Add(StatType.FireCumulativeValue, new Stat());
        stats.Add(StatType.IceDamage, new Stat());
        stats.Add(StatType.CurIceValue, new Stat());    
        stats.Add(StatType.IceCumulativeValue, new Stat());
        stats.Add(StatType.ElectricDamage, new Stat());
        stats.Add(StatType.CurElectricValue, new Stat());
        stats.Add(StatType.ElectricCumulativeValue, new Stat());
    }
    
    protected Stat GetStat(StatType stype)
    {
        if (!stats.ContainsKey(stype))
        {
            return null;
        }
        return stats[stype];
    }

    public void InitStats(StatType stype, float value)
    {
        SetValue(stype, value,false);
    }

    public float GetValue(StatType stype)
    {
        if (stats.ContainsKey(stype))
        {
            return  stats[stype].GetValue();
        }
        
        return 0;
    }

    public void SetValue(StatType stype, float value,bool  isModify)
    {
        if (stats.ContainsKey(stype))
        {
            if (!isModify)
            {
                stats[stype].SetValue(value);
            }
            else
            {
                if (value>0)
                {
                    stats[stype].AddAddModifier(value);
                }else
                {
                    stats[stype].AddSubModifier(value);
                }
                
            }
        }
    }
    
    #endregion

    #region 伤害与恢复
    public virtual DamegResult DoDamage(DamgeInfo info)
    {
        var  attacker = info.attacker;//攻击者
        var   target = info.targeter;//目标者
        var result = new DamegResult();
        //是否被闪避
        if (target.DoDodge(ref result)) return result;
        //是否暴击
        var  value = info.damage;
        //是否是易伤状态
        if (target.IsEasyDamage())
        {
            value *= 1.5f;
        }
        value = attacker.DoCrit(value,target, ref result);
        //是否可以消耗护甲值抵消
        value = target.DoDefense(value, ref result);
        if (value>0&&!isDead)
        {
            TakeDamage(value);
            //result.physicalDamage = value;
            Debuger.LogGreen($"{target.name}受到了{value}物理伤害");
        }
        //魔法伤害
        target.DoMagicDamage(StatType.FireDamage,attacker.GetValue(StatType.FireDamage),ref result);   
        target.DoMagicDamage(StatType.IceDamage,attacker.GetValue(StatType.IceDamage),ref result);
        target.DoMagicDamage(StatType.ElectricDamage,attacker.GetValue(StatType.ElectricDamage),ref result);
        //魔法异常累计
        target.AddMagicCumulativeValue(StatType.CurFireValue,attacker,ref result);
        target.AddMagicCumulativeValue(StatType.CurIceValue,attacker,ref result);
        target.AddMagicCumulativeValue(StatType.CurElectricValue,attacker,ref result);
        return  result;
    }
    private bool DoDodge(ref DamegResult result)
    {
        if (Random.Range(0,1f) < GetValue(StatType.DodgeRate))
        {   
            //result.isDodge = true;
            OnDodge?.Invoke();
            Debuger.LogYellow($"{name}闪避了");
            {
                return true;
            }
        }

        return false;
    }

    private float DoDefense(float value, ref DamegResult result)
    {
        var curDefense = GetValue(StatType.CurDefense);
        if (curDefense>0)
        {
            var maxDefense = GetValue(StatType.MaxDefense);
            var defenceDamage = Mathf.Clamp(value - curDefense, 0, value);//被格挡后的伤害
            Debuger.LogYellow($"{name}格挡了{value-defenceDamage}伤害");
            curDefense = Mathf.Clamp(curDefense - value, 0, maxDefense);//剩余护甲
            SetValue(StatType.CurDefense, curDefense,false);
            OnReduceDefense?.Invoke(curDefense/maxDefense);
            result.isDefend = true;
            value = defenceDamage;
        }

        return value;
    }

    private float DoCrit(float value,CharacterBase target, ref DamegResult result)
    {
        if (Random.Range(0,1f) < GetValue(StatType.CritRate))
        {
            value *= GetValue(StatType.CritDamage);
            //result.isCrit = true;
            target.OnCrit?.Invoke(value);//触发暴击伤害显示
            Debuger.LogYellow($"{name}暴击了");
            
        }

        return value;
    }

    //魔法异常累积
    public void AddMagicCumulativeValue(StatType sType,CharacterBase attacker, ref DamegResult result)
    {
        if (isBurning||isFrozen||isEasyDamage)//处于异常状态
        {
            return;
        }
        var curMagicCumulativeValue = GetValue(sType);
        var  value = 0f;
        switch (sType)
        {
            case  StatType.CurFireValue:
                value = attacker.GetValue(StatType.FireCumulativeValue);
                break;
            case  StatType.CurIceValue:
                value = attacker.GetValue(StatType.IceCumulativeValue);
                break;
            case  StatType.CurElectricValue:
                value = attacker.GetValue(StatType.ElectricCumulativeValue);
                break;
        }
        //魔法抗性
        var  magicResistance = GetValue(StatType.MagicResistance);
        //累计值 += (value-value*magicResistance*0.1)
        curMagicCumulativeValue += (value-value*magicResistance*0.1f);
        if (curMagicCumulativeValue>=100)//陷入异常
        {
            if (sType==StatType.CurFireValue)
            {
                isBurning = true;   
                burningTime = Setting.burningTime;
                //burnDely = Setting.burningDely;
                //result.isBurning = true;
                OnFireStatusStart?.Invoke();
                Debuger.LogRed($"{name}陷入火焰异常");
            }
            if (sType==StatType.CurIceValue)
            {
                isFrozen = true;
                frozenTime = Setting.frozenTime;    
                //result.isFrozen = true;
                OnIceStatusStart?.Invoke();
                Debuger.LogRed($"{name}陷入寒冷异常");
            }
            if (sType==StatType.CurElectricValue)
            {
                isEasyDamage = true;
                easyDamageTime = Setting.easyDamageTime;    
                //result.isEasyDamage = true;
                OnElectricStatusStart?.Invoke();
                Debuger.LogRed($"{name}陷入电异常");
            }
            curMagicCumulativeValue = 0;
        }
        SetValue(sType, curMagicCumulativeValue,false);
    }
    
    private void DoMagicDamage(StatType sType, float damage, ref DamegResult result)
    {
        if (isBurning||isFrozen||isEasyDamage)//处于异常状态
        {
            return;
        }
        var  magicResistance = GetValue(StatType.MagicResistance);
        var finalDamage = damage -  damage*magicResistance*0.1f;
        
        if (finalDamage>0&&!isDead)
        {
            TakeDamage(finalDamage);
            if (sType==StatType.FireDamage)
            {
                OnFireDamage ?.Invoke(finalDamage);
            }
            if (sType==StatType.IceDamage)
            {
                OnIceDamage ?.Invoke(finalDamage);
            }
            if (sType==StatType.ElectricDamage)
            {
                OnElectricDamage ?.Invoke(finalDamage);
            }
            Debuger.LogGreen($"{name}受到了{finalDamage}{sType.ToString()}魔法伤害");
        }
    }


    private void DoBuffDamage(float damage)
    {
        if (isDead)
        {
            return;
        }
        TakeDamage(damage);
    }
    
    public virtual void TakeDamage(float value)
    {
        var currentHealth = GetValue(StatType.CurrentHealth);
        var  maxHealth = GetValue(StatType.MaxHealth);
        currentHealth = Mathf.Clamp(currentHealth - value, 0, maxHealth);
        SetValue(StatType.CurrentHealth, currentHealth,false);
        OnReduceHealth?.Invoke(currentHealth/maxHealth);
        if (GetValue(StatType.CurrentHealth)<=0)
        {
            isDead = true;
        }
        if (isDead)
        {
            //通知死亡
            owner.GoDead();
            OnDead?.Invoke();
        }
        Debuger.LogOrange(($"{name}当前血量{GetValue(StatType.CurrentHealth)}"));
    }
    
    public void Heal(float value, bool isModify)
    {
        if (isDead)
        {
            return;
        }
        var currentHealth = GetValue(StatType.CurrentHealth);
        var  maxHealth = GetValue(StatType.MaxHealth);
        currentHealth = Mathf.Clamp(currentHealth + value , 0, maxHealth);
        SetValue(StatType.CurrentHealth, currentHealth,isModify);
        Debuger.LogGreen($"{name}恢复了{value}");
    }
    
    #endregion
    
}
